# module name dbmodel.py
# $Id: dbmodel.py 70fe0286d122 2013/07/17 05:39:39 pgurumur $
# Copyright (c) 2013 Prabhu Gurumurthy <pgurumur@gmail.com>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# File dbmodel.py generated on Wed, July 10, 2013 15:36:53 PM
#
__version__  = "$Revision: 70fe0286d122 $"
__author__   = "$Author: pgurumur $"
__modified__ = "$Date: 2013-07-17 05:39:39Z $"

import datetime
from sqlalchemy.ext.declarative import declarative_base, DeclarativeMeta

Base = declarative_base()
tableList = {}

"""
def decoratorFunctionWithArguments(arg1, arg2, arg3):
    def wrap(f):
        print "Inside wrap()"
        def wrapped_f(*args):
            print "Inside wrapped_f()"
            print "Decorator arguments:", arg1, arg2, arg3
            f(*args)
            print "After f(*args)"
        return wrapped_f
    return wrap

def validate(function):
   def wrapper(*args, **kwargs):
      cls = args[0]
      columns = cls.t.c
      for key, value in kwargs.items():
         if key not in columns:
            raise ModelError("invalid column: %s" %key)
         else:
            setattr(cls, key, value)

      cls.updated = datetime.datetime.now()
      function(*args, **kwargs)

   return wrapper
"""

def validate(**kwargs):
   flag = None
   if "update" in kwargs:
      flag = kwargs["update"]

   def wrap(function):
      def wrapper(*args, **kwargs):
         cls = args[0]
         columns = cls.t.c
         for key, value in kwargs.items():
            if key not in columns:
               raise ModelError("invalid column: %s" %key)
            else:
               setattr(cls, key, value)

         if flag:
            cls.updated = datetime.datetime.now()

         function(*args, **kwargs)

      return wrapper

   return wrap


def mapperargs(tablename):
   retval = {}
   if tablename:
      retval['polymorphic_identity'] = tablename
      retval['concrete'] = True
   else:
      raise ModelError("no tablename defined")

   return retval

def table(**keywords):
   if "name" not in keywords:
      raise ModelError("mandatory keyword 'name' missing")

   if not isinstance(keywords["name"], str):
      raise ModelError("name has to be a string")

   if "parent" not in keywords:
      raise ModelError("mandatory keyword 'parent' missing")

   if not isinstance(keywords["parent"], DeclarativeMeta):
      raise ModelError("invalid instance for table %s" %args[1])

   base = keywords["parent"]
   name = keywords["name"]
   base.__tablename__ = name

   def decorator(cls):
      cls.__mapper_args__ = mapperargs(name)
      tableList[name] = cls
      return cls

   return decorator

class ModelError(Exception):
   pass

class ModelBase(Base):
   __abstract__ = True
   __session__ = None
   __engine__ = None

   def __init__(self, *args, **kwargs):
      super(ModelBase, self).__init__()
      self._query = None
      self._uquery = None

   def __unicode__(self):
      return unicode(str(self))

   def __repr__(self):
      return repr(str(self))

   def __len__(self):
      return self.q.count()

   def __getitem__(self, key):
      raise NotImplementedError()

   @property
   def t(self):
      return self.__table__

   @property
   def q(self):
      retval = None
      if self.t is not None:
         retval = self.__session__.query(self.t)

      return retval

   def get_col(self, name):
      retval = None
      if hasattr(self.t.c, name):
         retval = getattr(self.t.c, name)
      else:
         raise ModelError("invalid column name %s" %name)

      return retval

   def save(self, *args, **kwargs):
      raise NotImplementedError()

   def update(self, *args, **kwargs):
      raise NotImplementedError()

